#include "File.h"
#include <cstring>
#include <errno.h>
#include <sstream>
#include <iostream>

#include <BaseException.h>
#include <Constantes.h>

File :: File()
:m_Fd(-1), m_Nombre("")
{
}

File :: File ( const std::string& nombre )
:m_Fd(-1), m_Nombre("")
{
	this->abrir(nombre);
}

File :: ~File () {
	this->cerrar();
}

std::string File::getFileName() const
{
	return m_Nombre;
}

bool File::crear(const std::string& nombre, const int creationMode)
{
	bool creado = false;
	bool exists = this->existe(nombre);
	if(creationMode == CreationMode::CREAR_SI_NO_EXISTE)
	{
		if(!exists)
		{
			this->abrir(nombre);
			this->cerrar();
			creado = true;
		}
		else
		{
			this->m_Nombre = nombre;
		}
	}
	else if(creationMode == CreationMode::NO_DEBE_EXISTIR)
	{
		if(exists)
			throw BaseException("El archivo existe");
		
		// Creo el archivo
		this->abrir(nombre);
		this->cerrar();
		creado = true;
	}
	else if(creationMode == CreationMode::DEBE_EXISTIR)
	{
		if(!exists)
			throw BaseException("El archivo no existe");
		
		this->m_Nombre = nombre;
	}
	else
	{
		throw BaseException("El modo de creacion es invalido");
	}
	return creado;
}

bool File::existe(const std::string& nombre)
{
	int fd = open ( nombre.c_str(),O_WRONLY);
	if(fd < 0)
	{
		return false;
	}
	close(fd);
	return true;
}

void File::abrir(const std::string& nombre)
{
	if(m_Fd >= 0)
		throw BaseException("El archivo ya esta abierto");
	
	this->m_Fd = open ( nombre.c_str(),O_CREAT|O_WRONLY,0777 );
	if(this->m_Fd < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al abrir el archivo " << nombre;
		eMsg << ". Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	this->m_Nombre = nombre;
}

ssize_t File :: append( const void* buffer,const ssize_t buffsize ) const
{
	if(lseek ( this->m_Fd,0,SEEK_END ) < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al posicionarse en el archivo ";
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	ssize_t cantBytesEscritos = write ( this->m_Fd,buffer,buffsize );
	if(cantBytesEscritos < 0)
	{
		std::stringstream eMsg;
		eMsg << "Ocurrio un error al escribir en el archivo " << m_Nombre;
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str());
	}
	return cantBytesEscritos;
}

void File::cerrar()
{
	if(this->m_Fd > 0)
	{
		close ( this->m_Fd );
		this->m_Fd = -1;
	}
}

void File::eliminar()
{
	this->cerrar();
	if(!m_Nombre.empty())
	{
		if(unlink ( m_Nombre.c_str() ) < 0)
			std::cerr << "Ocurrio un error al borrar el archivo " << m_Nombre << std::endl;
	}
}
